/* * JVMRuntimeClient.java * * Created on March 9, 2007, 2:44 PM * * Copyright (c) Sun Microsystems, 2007 - All rights reserved. */ package com.jvmruntime; import java.io.File; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.util.logging.Logger; import javax.management.remote.JMXServiceURL; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; import java.lang.management.RuntimeMXBean; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.management.MBeanServerConnection; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; /** * Class JVMRuntimeClient - Shows how to programmatically connect to * a running VM and interact with its RuntimeMXBean. * * @author Sun Microsystems, 2007 - All rights reserved. */ public class JVMRuntimeClient { /** * A logger for this class. **/ private static final Logger LOG = Logger.getLogger(JVMRuntimeClient.class.getName()); /** Creates a new instance of Main */ public JVMRuntimeClient() { } /** * A helper class to analyze the command line and create a JMXServiceURL. * Allows to pass a JMXServiceURL, a host and port, or a VM PID. **/ public static class ConnectionArgs { private static final String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress"; public final JMXServiceURL jmxURL; final public String SYNTAX = "JVMRuntimeClient -url <jmx-url> " + "| -port <port-number> [-host <host-or-ip] " + "| -pid <pid> | -help"; public ConnectionArgs(String[] args) { jmxURL = parseArgs(args); } public final JMXServiceURL getJMXServiceURL() { return jmxURL; } private JMXServiceURL parseArgs(String[] args) { String host = null; int port = 0; String pid = null; JMXServiceURL serviceURL = null; for (int i=0;i<args.length;i++) { if (args[i].startsWith("-url")) { // The '-url' option will let you specify a JMXServiceURL // on the command line. This is an URL that begins with // service:jmx:<protocol> // if (host != null) throwSyntaxError( "-url and -host are mutually exclusive"); if (pid != null) throwSyntaxError( "-pid and -url are mutually exclusive"); if (port > 0) throwSyntaxError( "-port and -url are mutually exclusive"); if (++i >= args.length) throwSyntaxError( "missing JMXServiceURL after -url"); try { serviceURL = new JMXServiceURL(args[i]); } catch (Exception x) { throwSyntaxError("bad JMXServiceURL after -url: " + x); } continue; } else if (args[i].startsWith("-host")) { // The '-host' and '-port' options will let you specify a host // and port, and from that will construct the JMXServiceURL of // the default RMI connector, that is: // service:jmx:rmi:///jndi/rmi://<host>:<port>/jmxrmi" // if (serviceURL != null) throwSyntaxError("-url and -host are mutually exclusive"); if (pid != null) throwSyntaxError("-pid and -host are mutually exclusive"); if (++i >= args.length) throwSyntaxError("missing host after -host"); try { InetAddress.getByName(args[i]); host = args[i]; } catch (Exception x) { throwSyntaxError("bad host after -url: " + x); } } else if (args[i].startsWith("-port")) { // The '-host' and '-port' options will let you specify a host // and port, and from that will construct the JMXServiceURL of // the default RMI connector, that is: // service:jmx:rmi:///jndi/rmi://<host>:<port>/jmxrmi" // if (serviceURL != null) throwSyntaxError("-url and -port are mutually exclusive"); if (pid != null) throwSyntaxError("-pid and -port are mutually exclusive"); if (++i >= args.length) throwSyntaxError("missing port number after -port"); try { port = Integer.parseInt(args[i]); if (port <= 0) throwSyntaxError("bad port number after -port: " + "must be positive"); } catch (Exception x) { throwSyntaxError("bad port number after -port: " + x); } } else if (args[i].startsWith("-pid")) { // The '-pid' and option will let you specify the PID of the // target VM you want to connect to. It will then use the // attach API to dynamically launch the JMX agent in the target // VM (if needed) and to find out the JMXServiceURL of the // the default JMX Connector in that VM. // if (serviceURL != null) throwSyntaxError("-url and -pid are mutually exclusive"); if (port > 0) throwSyntaxError("-port and -pid are mutually exclusive"); if (++i >= args.length) throwSyntaxError("missing pid after -pid"); try { pid = args[i]; } catch (Exception x) { throwSyntaxError("bad pid after -pid: " + x); } } else if (args[i].startsWith("-help")) { final List<String> vmlist = new ArrayList<String>(); for (VirtualMachineDescriptor vd : VirtualMachine.list()) { vmlist.add(vd.id()); } System.err.println(SYNTAX); System.err.println("Running JVMs are: "+vmlist); throw new IllegalArgumentException(SYNTAX); } else { throwSyntaxError("Unknown argument: "+args[i]); } } // A JMXServiceURL was given on the command line, just use this. // if (serviceURL != null) return serviceURL; // A -host -port info was given on the command line. // Construct the default RMI JMXServiceURL from this. // if (port > 0) { if (host == null) host = "localhost"; try { return new JMXServiceURL("service:jmx:rmi:///jndi/rmi://"+ host+":"+port+"/jmxrmi"); } catch (Exception x) { throwSyntaxError("Bad host or port number: "+x); } } // A PID was given on the command line. // Use the attach API to find the target's connector address, and // start it if needed. // if (pid != null) { JMXServiceURL retVal = null; try { retVal = getURLForPid(pid); if(retVal == null){ retVal = extractJMXServiceURL(pid); } } catch (Exception x) {} if(retVal == null){ try { retVal = extractJMXServiceURL(pid); } catch (Exception x) { } } if(retVal == null) { throwSyntaxError("cannot attach to target vm "+pid); } return retVal; } final List<String> vmlist = new ArrayList<String>(); for (VirtualMachineDescriptor vd : VirtualMachine.list()) { vmlist.add(vd.id()); } throwSyntaxError("missing argument: "+ "-port | -url | -pid | -list" +"\\n\\tRunning VMs are: "+vmlist); // Unreachable. return null; } private void throwSyntaxError(String msg) { System.err.println(msg); System.err.println(SYNTAX); throw new IllegalArgumentException(msg); } private JMXServiceURL extractJMXServiceURL(String pid) throws Exception { String serviceURL = null; int ipid; try { ipid = Integer.parseInt(pid); serviceURL = sun.management.ConnectorAddressLink.importFrom(ipid); } catch(Exception e) { System.out.println("Cannot find process pid"); } if(serviceURL == null) return null; else return new JMXServiceURL(serviceURL); } private JMXServiceURL getURLForPid(String pid) throws Exception { // attach to the target application final VirtualMachine vm = VirtualMachine.attach(pid); // get the connector address String connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS); // no connector address, so we start the JMX agent if (connectorAddress == null) { String agent = vm.getSystemProperties().getProperty("java.home") + File.separator + "lib" + File.separator + "management-agent.jar"; vm.loadAgent(agent); // agent is started, get the connector address connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS); assert connectorAddress != null; } return new JMXServiceURL(connectorAddress); } } //////////////////////////////////////////////////////////////////// /** * get the PID of the running JVM. NOTE: this may not work on all platforms/jvms */ public static String getProcessIDString() { RuntimeMXBean mxbean = java.lang.management.ManagementFactory.getRuntimeMXBean(); String jvmNameStr = mxbean.getName(); System.err.println("jvmNameStr->" + jvmNameStr); //4072@THPDEVL11 int atIndex = jvmNameStr.indexOf('@'); if( atIndex < 0 ) return null; String pid = jvmNameStr.substring(0, atIndex); //System.err.println("pid->" + pid); return pid; }//method /** * Get current Java Spec as an integer. */ public static void dumpSystemProperties() { Properties prop = System.getProperties(); prop.list(System.out); } // dumpSystemProperties /** * @param args the command line arguments: * must be -url <jmx-url>, * or -port <port-number> [-host <host-or-ip], * or -pid <pid>, * or -help */ public static void main(String[] args) throws Exception { // dumpSystemProperties(); // String pid = getProcessIDString(); // String[] args2 = {"-pid", pid}; String[] args2 = {"-port", "9010"}; // Parse arguments. final ConnectionArgs cArgs = new ConnectionArgs(args2); // Get target's URL final JMXServiceURL target = cArgs.getJMXServiceURL(); System.out.println("jmxrmi URL: "+target); // Connect to target (assuming no security) final JMXConnector connector = JMXConnectorFactory.connect(target); // Get an MBeanServerConnection on the remote VM. final MBeanServerConnection remote = connector.getMBeanServerConnection(); final RuntimeMXBean remoteRuntime = ManagementFactory.newPlatformMXBeanProxy( remote, ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); System.out.println("Target VM is: "+remoteRuntime.getName()); System.out.println("Started since: "+remoteRuntime.getUptime()); System.out.println("With Classpath: "+remoteRuntime.getClassPath()); System.out.println("And args: "+remoteRuntime.getInputArguments()); connector.close(); Thread.sleep(1000000); } }